home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1992 June: ROMin Holiday / ADC Developer CD (1992-06) (''ROMin Holiday'')_iso / Developer Connection - 06-1992.iso / Tools & Apps / Testing & Debugging / TV-Man Package / With Source Version / Source / TV-Man.Sound.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-11-13  |  29.8 KB  |  1,099 lines  |  [TEXT/MPS ]

  1. /*------------------------------------------------------------------------------
  2. #
  3. #    TV-Man.Sound.c
  4. #
  5. #    Copyright © Apple Computer, Inc. 1989-1990
  6. #    All rights reserved.
  7. #
  8. #    
  9. #    All the pertinent code which provides both the control of the beep style as
  10. #    well as the generation of the beep itself is found in this file.
  11. #
  12. #    In order to have an evironment which predictable events happen several definitions
  13. #    must be established. The most critical is in the file architecture. Each functional
  14. #    block will have its own source and header file. The main project file,  in this
  15. #    case TV-Man, will have its header file included with all other files. This will
  16. #    allow for global constants. The utility source file shall contain functions that
  17. #    are general purpose in nature and that can be used by all other functions. These
  18. #    are intended not to be application or major block specific. In order for this to be 
  19. #    accomodated all functions in the utility source file must use only the information
  20. #    that is passed to them or information that can be gleaned from the system via
  21. #    toolbox calls. There will be no header file associated with the utility file as this
  22. #    will destroy the intent of the utilities.
  23. #
  24. #    There are several files which contain information which is global in nature .These
  25. #    file are included in the main project header file. They are: x.Errors.h, x.Ext.h,
  26. #    x.Protos.h, x.Menus.h. The reason for containing them in seperate files is one of
  27. #    convienience and accesability. 
  28. #
  29. #
  30. #    Revision Log:
  31. #    
  32. #        8-21-91        RGK        Creation
  33. #
  34. #
  35. ------------------------------------------------------------------------------*/
  36.  
  37.  
  38. /* This is a list of all local includes necessary for this program.    */
  39.  
  40. #include "TV-Man.h"
  41. #include "TV-Man.Sound.h"
  42.  
  43.  
  44.  
  45.  
  46. /*-------------------------------------------------------------------------------*/
  47. /*    These are the globals used in the making of sounds and the sound dialog box    */
  48.  
  49. BeepChan    gSopranoChan;        /*    beep channel 1    (not sound a channel)    */
  50. BeepChan    gAltoChan;            /*    beep channel 2                            */
  51. BeepChan    gTenorChan;            /*    beep channel 3                            */
  52. BeepChan    gBassChan;            /*    beep channel 4                            */
  53. BeepChan    gTestChan;            /*    beep channel for the test beep            */
  54.  
  55. Beep        gBeepData;            /*    global beep variables used by the dialog box */
  56. Beep        gBeepDataT;            /*    global beep variables for test beep        */
  57.  
  58.  
  59.  
  60.  
  61.  
  62.  
  63. /*----------------------------------------------------------------------------------*/
  64. /*----------------------------------------------------------------------------------*/
  65. /*    This first section is the interface calls between BeepMaster.lib library and the
  66.     outside world. All the interface calls are in pascal for use with the CPU
  67.     Diagnostics Sequencer.    */
  68.  
  69.  
  70. /*----------------------------------------------------------------------------------*/
  71. /*    This will return the version number of the sound stuff. This is only
  72.     used as part of the BeepMgr.lib which is useable in other programs    */
  73.  
  74. pascal long SoundVersion()
  75. {
  76.     return(SndVerNumber);
  77. }/* SoundVersion */
  78.  
  79.  
  80.  
  81.  
  82.  
  83.  
  84. /*----------------------------------------------------------------------------------*/
  85. /*    This will initalize all the necessary globals for the Sound Stuff.     */
  86.  
  87. pascal void SoundInit()
  88. {
  89.     InitChannel(&gSopranoChan, rSopranoBData);
  90.     InitChannel(&gAltoChan, rAltoBData);
  91.     InitChannel(&gTenorChan, rTenorBData);
  92.     InitChannel(&gBassChan, rBassBData);
  93.     InitChannel(&gTestChan, rTestBData);
  94. }/* SoundInit */
  95.  
  96.  
  97.  
  98.  
  99.  
  100.  
  101. /*----------------------------------------------------------------------------------*/
  102. /*    This function will set all the beep enable flags. The call to "SoundCheck"
  103.     will start the Noise making.    */
  104. pascal void SoundEnable( void )
  105. {
  106.     SetAllSounds();
  107. }/* SoundEnable */
  108.  
  109.  
  110.  
  111.  
  112.  
  113.  
  114. /*----------------------------------------------------------------------------------*/
  115. /*    This function is designed to be called by the event loop. It is used to continue
  116.     a beep after the interrupt has identified that the sound queue has been emptied.
  117.     A beep channel is identified and the rest of the beep control processing is
  118.     called. However, before processing a beep channel the error flag is checked for
  119.     any previous errors, if so that beep channel is bypassed. */
  120.  
  121. pascal void SoundCheck(void)
  122. {
  123.     if(gSopranoChan.Error == false) ProcessBeep(&gSopranoChan);
  124.     if(gAltoChan.Error == false) ProcessBeep(&gAltoChan);
  125.     if(gTenorChan.Error == false) ProcessBeep(&gTenorChan);
  126.     if(gBassChan.Error == false) ProcessBeep(&gBassChan);
  127. }/* SoundCheck */
  128.  
  129.  
  130.  
  131.  
  132.  
  133.  
  134. /*----------------------------------------------------------------------------------*/
  135. /*    This function will dispose of the sound channel which will stop the beeping
  136.     immedatly.    */
  137. pascal void SoundStop(void)
  138. {
  139.     KillSoundChannels();
  140. }/* SoundStop */
  141.  
  142.  
  143.  
  144.  
  145. /*----------------------------------------------------------------------------------*/
  146. /*    This function will first clear all the beep enable flags and then dispose of the
  147.     sound channel which will stop the beeping immedatly.    */
  148. pascal void SoundDisable(void)
  149. {
  150.     ClearAllSounds();
  151.     KillSoundChannels();
  152. }/* SoundDisable */
  153.  
  154.  
  155.  
  156.  
  157.  
  158.  
  159.  
  160. /*----------------------------------------------------------------------------------*/
  161. /*    set up the Sound dialog box    */
  162.  
  163. pascal void SopranoControls()
  164. {
  165.     DoSoundControls(rSopranoBData);
  166. }
  167.  
  168.  
  169.  
  170.  
  171. /*----------------------------------------------------------------------------------*/
  172. /*    set up the Sound dialog box    */
  173.  
  174. pascal void AltoControls()
  175. {
  176.     DoSoundControls(rAltoBData);
  177. }
  178.  
  179.  
  180.  
  181.  
  182. /*----------------------------------------------------------------------------------*/
  183. /*    set up the Sound dialog box    */
  184.  
  185. pascal void TenorControls()
  186. {
  187.     DoSoundControls(rTenorBData);
  188. }
  189.  
  190.  
  191.  
  192.  
  193. /*----------------------------------------------------------------------------------*/
  194. /*    set up the Sound dialog box    */
  195.  
  196. pascal void BassControls()
  197. {
  198.     DoSoundControls(rBassBData);
  199. }
  200.  
  201.  
  202.  
  203. /*----------> the end of the library interface   <---------------------*/
  204.  
  205. /*----------------------------------------------------------------------------------*/
  206. /*    set up the Sound dialog box    */
  207.  
  208. void DoSoundControls(rsrc)
  209. short        rsrc;
  210. {
  211.     short        itemhit;
  212.     DialogPtr    dialog;
  213.     MenuHandle    menu;
  214.     BeepHdl        beephdl;
  215.  
  216.  
  217.     KillSoundChannels();
  218.  
  219.     dialog = GetNewDialog(rSounds,nil,(WindowPtr)-1);
  220.     if((dialog == nil) || (ResError() != noErr)) 
  221.     {
  222.         Error(eMinor, eMinorDialog);
  223.         return;
  224.     }
  225.     
  226. /* the following resource grab is not used here but is used by the functions which
  227.     follow. By getting the menu resource and checking it now we are in a better
  228.     position to recover from an error caused by not capturing the resource    */
  229.     
  230.     menu = GetMenu(rBeepMenu);
  231.     if((menu == nil) || (ResError() != noErr)) 
  232.     {
  233.         Error(eMinor, eMinorMenu);
  234.         return;
  235.     }
  236.  
  237. /*    Set up the Beep data globals    */
  238.     beephdl = (BeepHdl)GetResource('beep', rsrc);
  239.     if((beephdl == nil) || (ResError() != noErr)) 
  240.     {
  241.         Error(eMinor, eMinorRsrc);
  242.         return;
  243.     }
  244.     
  245.     HNoPurge((Handle)beephdl);        /* don't allow the resource to be purged    */
  246.     InitTheValues(dialog, beephdl);    /* set up all the values    */
  247.     ShowWindow(dialog);
  248.             
  249.  
  250. /*    Now we will use the standard Modal dialog process to handle the user. The sound filter
  251.     function will handle all the special cases during this process. The 2 choices upon
  252.     returning are the cancel and done. If cancel leave without changing resource    */
  253.     
  254.      while(itemhit != BeepCancelId)
  255.     {
  256.         ModalDialog((ModalFilterProcPtr)SoundFilter, &itemhit);
  257.         if(itemhit == BeepDoneId)
  258.         {
  259.             FullRangeCheck(dialog);
  260.             SaveTheValues( dialog, beephdl, true);
  261.             break;
  262.         }
  263.     }
  264.     HPurge((Handle)beephdl);        /* allow purgeing again    */
  265.     DisposeMenu(menu);
  266.     DisposeDialog(dialog);
  267.     
  268. /*    gSopranoChan.Error = false;             set the sound error to false to signify that a
  269.                                         new sound setup is avaliable    */
  270. }/* DoSound */
  271.  
  272.  
  273.  
  274.  
  275.  
  276.  
  277. /*---------------------------------------------------------------------------------------*/
  278. /*    This function is used to draw the ring around the done button.    */
  279.     
  280. pascal void DrawBeepDone(dialog, item)
  281. DialogPtr    dialog;
  282. short        item;
  283. {
  284.     short        itemtype;
  285.     Rect        itemrect;
  286.     Handle        itemhdl;
  287.     PenState    savepen;
  288.     
  289.     GetPenState(&savepen);
  290.     GetDItem(dialog, item, &itemtype, &itemhdl, &itemrect);
  291.     PenSize(3, 3);
  292.     FrameRoundRect(&itemrect, 16, 16);
  293.     SetPenState(&savepen);
  294. }/*    DrawBeepDone    */
  295.  
  296.  
  297.  
  298.  
  299.  
  300.  
  301.  
  302.  
  303. /*---------------------------------------------------------------------------------------
  304.     This function is used to draw useritems in dialog boxes. The item number as well as
  305.     handle to the dialog box is needed.    */
  306.     
  307. pascal void DrawBeepType(dialog, item)
  308. DialogPtr    dialog;
  309. short        item;
  310. {
  311.     short        itemtype;
  312.     Rect        itemrect;
  313.     Handle        itemhdl;
  314.     Str255        menutext;
  315.     
  316.     GetDItem(dialog, item, &itemtype, &itemhdl, &itemrect);
  317.     InsetRect(&itemrect, -1, -1);
  318.     GetItem(GetMenu(rBeepMenu), gBeepData.Type, menutext);
  319.     
  320. /* make the box and shadow it    */
  321.     FrameRect(&itemrect);
  322.     MoveTo(itemrect.right, itemrect.top + 2);
  323.     LineTo(itemrect.right, itemrect.bottom);
  324.     LineTo(itemrect.left + 2, itemrect.bottom);
  325.     
  326. /*    now add the text    */
  327.     MoveTo(itemrect.left + LeftMargin, itemrect.bottom - BottomMargin);
  328.     DrawString(menutext);
  329. }/*    DrawBeepType    */
  330.  
  331.  
  332.  
  333.  
  334.  
  335.  
  336. /*----------------------------------------------------------------------------------*/
  337. /*  This is the Sound dialog box filter function. This means all mouse events and 
  338.     key strokes are processed by this function as long as the Sound dialog box is
  339.     on the screen    */
  340.  
  341. pascal Boolean SoundFilter(dialog, event, itemhit)
  342. DialogPtr        dialog;
  343. EventRecord        *event;
  344. short            *itemhit;
  345.  
  346. {
  347.     char        key;
  348.     short        itemtype, itemid, part;
  349.     long        value;
  350.     Rect        itemrect;
  351.     Handle        itemhdl;
  352.     Point        mouseloc;
  353.     
  354.     SetPort(dialog);
  355.     switch(event->what)
  356.     {
  357.         case keyDown:
  358.         case autoKey:
  359.             key = event->message;
  360.             if((key == ENTERKEY) || (key == RETURNKEY))
  361.             {
  362.                 GetDItem(dialog, BeepDoneId, &itemtype, &itemhdl, &itemrect);
  363.                 HiliteControl((ControlHandle)itemhdl, 1);
  364.                 Delay(3, &value);
  365.                 *itemhit = BeepDoneId;
  366.                 return(true);
  367.             }
  368.             break;
  369.             
  370.         case mouseDown:
  371.             mouseloc = event->where;
  372.             GlobalToLocal(&mouseloc);
  373.             itemid = (FindDItem(dialog, mouseloc)) + 1; 
  374.             switch(itemid)
  375.             {
  376.                 case BeepEnableId:
  377.                     UpDateSlider(dialog, BeepVolumeId);
  378.                     UpDateSlider(dialog, BeepFreqId);
  379.                     GetDItem(dialog, BeepEnableId, &itemtype, &itemhdl, &itemrect);
  380.                     part = TrackControl((ControlHandle)itemhdl, mouseloc, (ProcPtr) -1);
  381.                     if(part == inCheckBox) ToggleControl((ControlHandle)itemhdl);
  382.                     return(true);
  383.                     break;
  384.                 
  385.                 case BeepTypeId:
  386.                     UpDateSlider(dialog, BeepVolumeId);
  387.                     UpDateSlider(dialog, BeepFreqId);
  388.                     DoBeepTypeMenu(dialog);
  389.                     return(true);
  390.                     break;
  391.                     
  392.                 case BeepVolumeCntlId:
  393.                     DoSliders(dialog, mouseloc, BeepVolumeCntlId); 
  394.                     return(true);
  395.                     break;
  396.                     
  397.                 case BeepFreqCntlId:
  398.                     DoSliders(dialog, mouseloc, BeepFreqCntlId); 
  399.                     return(true);
  400.                     break;
  401.                     
  402.                 case BeepDoneId:
  403.                     GetDItem(dialog, BeepDoneId, &itemtype, &itemhdl, &itemrect);
  404.                     HiliteControl((ControlHandle)itemhdl, true);
  405.                     Delay(3, &value);
  406.                     *itemhit = BeepDoneId;
  407.                     return(true);
  408.                     break;
  409.  
  410.                 case TestBeepId:
  411.                     TestTheBeep(dialog);
  412.                     return(true);
  413.                     break;
  414.                     
  415.                 case BeepCancelId:
  416.                     GetDItem(dialog, BeepCancelId, &itemtype, &itemhdl, &itemrect);
  417.                     HiliteControl((ControlHandle)itemhdl, true);
  418.                     Delay(3, &value);
  419.                     *itemhit = BeepCancelId;
  420.                     return(true);
  421.                     break;
  422.             }
  423.         FullRangeCheck(dialog);
  424.         break;
  425.     }
  426.     return(false);
  427. }/*    SoundFilter */
  428.  
  429.  
  430.  
  431.  
  432.  
  433.  
  434.  
  435.  
  436. /*----------------------------------------------------------------------------------*/
  437. /*    Lets set up all the values in the dialog boxes and all the other information needed
  438.     by the sound dialog box from the appointed resource.    */
  439.     
  440. void InitTheValues(dialog, beephdl)
  441. DialogPtr    dialog;
  442. BeepHdl        beephdl;
  443. {
  444.     short        itemtype;
  445.     Rect        itemrect; 
  446.     Handle        itemhdl;
  447.  
  448. /*    Initalize the necessary globals    */
  449.     gBeepData.Type = ((*beephdl)->Type) - (rBeepMenu * 10);
  450.     
  451. /*    make all the pertinent text boxes in the dialog reflect the actual values from
  452.     the beep resource    */
  453.     Short2Text((*beephdl)->Length, dialog, BeepLengthId);
  454.     Short2Text((*beephdl)->QTime, dialog, BeepQTimeId);
  455.     Short2Text((*beephdl)->Count, dialog, BeepCountId);
  456.     Short2Text((*beephdl)->Delay, dialog, BeepDelayId);
  457.     Short2Text((*beephdl)->Volume, dialog, BeepVolumeId);
  458.     Short2Text((*beephdl)->Freq, dialog, BeepFreqId);
  459.     
  460. /*    Set the Controls to the correct values.    */
  461.     GetDItem(dialog, BeepEnableId, &itemtype, &itemhdl, &itemrect);
  462.     SetCtlValue((ControlHandle)itemhdl, (Boolean)((*beephdl)->Enabled));
  463.     GetDItem(dialog, BeepVolumeCntlId, &itemtype, &itemhdl, &itemrect);
  464.     SetCtlValue((ControlHandle)itemhdl, ((*beephdl)->Volume) * -1);
  465.     GetDItem(dialog, BeepFreqCntlId, &itemtype, &itemhdl, &itemrect);
  466.     SetCtlValue((ControlHandle)itemhdl, ((*beephdl)->Freq) * -1);
  467.     
  468. /*    now set the beep type pop up menu    */
  469.     GetDItem(dialog, BeepTypeId, &itemtype, &itemhdl, &itemrect);
  470.     SetDItem(dialog, BeepTypeId, itemtype, (Handle)DrawBeepType, &itemrect);
  471.  
  472. /*    set the done button to indicate a default button    */
  473.     GetDItem(dialog, BeepDoneId, &itemtype, &itemhdl, &itemrect);
  474.     InsetRect(&itemrect, -4, -4);
  475.     SetDItem(dialog, DoneRingId, userItem, (Handle)DrawBeepDone, &itemrect);
  476.     
  477. /*    now depending on the resource data assigned the title will be changed    */
  478.     GetDItem(dialog, BeepTitleId, &itemtype, &itemhdl, &itemrect);
  479.     SetIText(itemhdl, (*beephdl)->Title);
  480. }/* InitTheValues */
  481.  
  482.  
  483.  
  484.  
  485.  
  486.  
  487.  
  488. /*----------------------------------------------------------------------------------*/
  489. /*    Lets save all the values in the dialog boxes and place them into the appointed 
  490.     resource. If the "doit" flag is false the resource will not be updated otherwise
  491.     it will. */
  492.     
  493. void SaveTheValues(dialog, beephdl, doit)
  494. DialogPtr    dialog;
  495. BeepHdl        beephdl;
  496. Boolean        doit;
  497. {    
  498.     short        itemtype;
  499.     Rect        itemrect; 
  500.     Handle        itemhdl;
  501.  
  502. /*    put all the new values into the Beep recource data    */
  503.     GetDItem(dialog, BeepEnableId, &itemtype, &itemhdl, &itemrect);
  504.     (*beephdl)->Enabled = GetCtlValue((ControlHandle)itemhdl);
  505.     (*beephdl)->Type = gBeepData.Type + (rBeepMenu * 10);
  506.     (*beephdl)->Length = Text2Short(dialog, BeepLengthId);
  507.     (*beephdl)->QTime = Text2Short(dialog, BeepQTimeId);
  508.     (*beephdl)->Count = Text2Short(dialog, BeepCountId);
  509.     (*beephdl)->Delay = Text2Short(dialog, BeepDelayId);
  510.     (*beephdl)->Volume = Text2Short(dialog, BeepVolumeId);
  511.     (*beephdl)->Freq = Text2Short(dialog, BeepFreqId);
  512.     
  513.     if(doit == true)
  514.     {
  515. /* Now lets change the Beep resource    */
  516.         ChangedResource((Handle)beephdl);    /* mark it changed    */
  517.         WriteResource((Handle)beephdl);        /* make the change permanent    */
  518.     }
  519. }/* SaveTheValues */
  520.  
  521.  
  522.  
  523.  
  524.  
  525.  
  526. /*----------------------------------------------------------------------------------*/
  527. /*    This function puts up the Beep Type menu. As long as the user whishes to interact
  528.     with the Beep Type menu program control will stay in this function. The
  529.     'PopUpMenuSelect' function will capture control and handle the highlighting and
  530.     selection of the menu items.    */
  531.  
  532. void DoBeepTypeMenu(dialog)
  533. DialogPtr    dialog;
  534. {
  535.     short        itemtype, olditem;
  536.     Rect        itemrect, box;
  537.     Handle        itemhdl;
  538.     MenuHandle    menu;
  539.     long        value;
  540.  
  541.     GetDItem(dialog, BeepTypeId, &itemtype, &itemhdl, &itemrect);
  542.     
  543. /*    we are now going to get a resource, normally a safty measure would entail checking
  544.     for errors after the GetResource call. However, early in this whole dialog process 
  545.     I got and checked this resource in a place where it was more appropreate to handle
  546.     the error.    */    
  547.     menu = GetMenu(rBeepMenu);
  548.     
  549.     InsertMenu(menu, -1);
  550.     CalcMenuSize(menu);                    /*    for a Menu Mgr Bug    */
  551.     olditem = gBeepData.Type;                /*    save the old type    */
  552.     CheckItem(menu, gBeepData.Type, true);    /*    and check it    */
  553.                     
  554. /*    globalize the menu box and aquire the new selection    */
  555.     box = itemrect;
  556.     LocalToGlobal(&TopLeft(box));
  557.     value = PopUpMenuSelect(menu, box.top, box.left, gBeepData.Type);
  558.     gBeepData.Type = LoWord(value);
  559.                     
  560. /* now lets uncheck the old type, check the new type and erase the old selection
  561.     and put in the new one (for the current dialog box view)    */
  562.     CheckItem(menu, olditem, false);
  563.     CheckItem(menu, gBeepData.Type, true);
  564.     EraseRect(&itemrect);
  565.     DrawBeepType(dialog, BeepTypeId);
  566.     DeleteMenu(rBeepMenu);
  567. }/* DoBeepTypeMenu */
  568.  
  569.  
  570.  
  571.  
  572.  
  573.  
  574.  
  575. /*----------------------------------------------------------------------------------*/
  576. /*    This function is called to force all the controls an edit boxes to be matched to
  577.     their correct limits. The process of the functions that this function calls will
  578.     check the values and if the limits are exceeded change the values to the closest
  579.     limit    */
  580.  
  581. void FullRangeCheck(dialog)
  582. DialogPtr    dialog;
  583. {
  584.     UpDateSlider(dialog, BeepVolumeId);
  585.     UpDateSlider(dialog, BeepFreqId);
  586.     RangeCheckShort(dialog, BeepLengthId, LengthMin, LengthMax);
  587.     RangeCheckShort(dialog, BeepQTimeId, QTimeMin, QTimeMax);
  588.     RangeCheckShort(dialog, BeepCountId, CountMin, CountMax);
  589.     RangeCheckShort(dialog, BeepDelayId, DelayMin, DelayMax);
  590. }/* FullRangeCheck */
  591.  
  592.  
  593.  
  594.  
  595.  
  596.  
  597.  
  598. /*----------------------------------------------------------------------------------*/
  599. /*    This function is called when a mouse event has been found in a scroll bar. The
  600.     display area of the slider control is by definition the next item id. This structure
  601.     allows this generic type of function to keep the corrisponding edit box current
  602.     with the value of the slider. Also remember the value contained in the controls
  603.     are negative requiring the sign adjustment by the "* -1".    */
  604.  
  605. void DoSliders(dialog, mouseloc, itemid)
  606. DialogPtr    dialog;
  607. Point        mouseloc;
  608. short        itemid;
  609. {
  610.     short            value;
  611.     ControlHandle    control;
  612.  
  613.     if(FindControl(mouseloc, dialog, &control) == inThumb)
  614.     {
  615.         value = TrackControl(control, mouseloc, (ProcPtr)-1);
  616.     }
  617.     else
  618.     {
  619.         value = TrackControl(control, mouseloc, (ProcPtr)SoundScroll);
  620.     }
  621.     value = GetCtlValue(control) * (-1);
  622.     Short2Text(value, dialog, itemid + 1);
  623. }/* DoSliders */
  624.  
  625.  
  626.  
  627.  
  628.  
  629.  
  630. /*----------------------------------------------------------------------------------*/
  631. /*    This function updates the slider controls based on the corrisponding edit box.
  632.     The item Id passed must be the Id of the text box. This function will determine
  633.     the appropreate control to adjust. Also if the value in the edit box is over the
  634.     limit of the control the edit box will be modified to reflect the limit and the
  635.     control will be updated accordingly.    */
  636.  
  637. void UpDateSlider(dialog, itemid)
  638. DialogPtr    dialog;
  639. short        itemid;
  640. {
  641.     short        itemtype, textvalue, value;
  642.     Rect        itemrect; 
  643.     Handle        itemhdl;
  644.  
  645.     GetDItem(dialog, itemid, &itemtype, &itemhdl, &itemrect);
  646.     textvalue = Text2Short(dialog, itemid) * (-1);
  647.     GetDItem(dialog, itemid - 1, &itemtype, &itemhdl, &itemrect);
  648.     value = CheckControlRange(textvalue, (ControlHandle)itemhdl);
  649.     if(value == textvalue)
  650.     {
  651.         SetCtlValue((ControlHandle)itemhdl, value);
  652.         return;
  653.     }
  654.     else
  655.     {
  656.         SetCtlValue((ControlHandle)itemhdl, value);
  657.         Short2Text(value * (-1), dialog, itemid);
  658.         return;
  659.     }
  660. }/* UpDateSlider */
  661.  
  662.  
  663.  
  664.  
  665.  
  666.  
  667. /*----------------------------------------------------------------------------------*/
  668. /*    This function is called when a mouse event has been found in a scroll bar. remember
  669.     the control values are all negative to allow for the fact the screen has "zero" as
  670.     the top. this allows larger absoute number to go up. However, all the calculations
  671.     and comparisons need to be "backwards".    */
  672.  
  673. pascal void SoundScroll(control, part)
  674. ControlHandle    control;
  675. short            part;
  676. {
  677.     short        value;    
  678.     
  679.     switch(part)
  680.     {
  681.         case inUpButton:
  682.             value = GetCtlValue(control) - 1;
  683.             if(value < GetCtlMin(control))
  684.             {
  685.                 value = GetCtlMin(control);
  686.             }
  687.             SetCtlValue(control, value);
  688.             break;
  689.             
  690.         case inDownButton:
  691.             value = GetCtlValue(control) + 1;
  692.             if(value > GetCtlMax(control))
  693.             {
  694.                 value = GetCtlMax(control);
  695.             }
  696.             SetCtlValue(control, value);
  697.             break;
  698.             
  699.         case inPageUp:
  700.             value = GetCtlValue(control) - JumpAmount(control, JumpCount);
  701.             if(value < GetCtlMin(control))
  702.             {
  703.                 value = GetCtlMin(control);
  704.             }
  705.             SetCtlValue(control, value);
  706.             break;
  707.             
  708.         case inPageDown:
  709.             value = GetCtlValue(control) + JumpAmount(control, JumpCount);
  710.             if(value > GetCtlMax(control))
  711.             {
  712.                 value = GetCtlMax(control);
  713.             }
  714.             SetCtlValue(control, value);
  715.             break;
  716.     }
  717. }/* SoundScroll */
  718.  
  719.  
  720.  
  721.  
  722.  
  723.  
  724. /*----------------------------------------------------------------------------------*/
  725. /*    This function is used by the dialog box to test the currently described beep.
  726.     This will not change the resource used by the actual program but uses a test
  727.     beep resource. This function will also lock into a loop that will test for key
  728.     inputs.If any key is pressed during the test beep the sound will stop and the
  729.     sound channel disposed of. This is not a recomended procedure because any Apple
  730.     Events (or any others) will not be processed. */
  731.  
  732. void TestTheBeep(dialog)
  733. DialogPtr        dialog;
  734. {
  735.     BeepHdl            beephdl;
  736.     SndChannelPtr    channel;
  737.     EventRecord        event;
  738.     short            itemtype;
  739.     Rect            itemrect; 
  740.     Handle            itemhdl;
  741.  
  742.  
  743. /*    Highlight the Test button while it is being pushed    */
  744.     GetDItem(dialog, TestBeepId, &itemtype, &itemhdl, &itemrect);
  745.     HiliteControl((ControlHandle)itemhdl, true);
  746.     
  747.     GetNextEvent(mUpMask, &event);
  748.     while(event.what != mouseUp)
  749.     {
  750.         GetNextEvent(mUpMask, &event);
  751.     }
  752.     HiliteControl((ControlHandle)itemhdl, false);
  753.  
  754. /* set up the test beep resource    */
  755.     beephdl = (BeepHdl)GetResource('beep', rTestBData);
  756.     if((beephdl == nil) || (ResError() != noErr)) 
  757.     {
  758.         Error(eMinor, eMinorRsrc);
  759.         return;
  760.     }
  761.     FullRangeCheck(dialog);
  762.     SaveTheValues(dialog, beephdl, false);
  763.     channel = DoSound(beephdl);
  764.  
  765. /*    now send a helpful message    */
  766.     GetDItem(dialog, BeepMessageId, &itemtype, &itemhdl, &itemrect);
  767.     SetIText(itemhdl, "\p))   Any key will kill Beeps.");
  768.  
  769.     if(channel != nil)
  770.     {
  771.         gTestChan.InProcess = true;
  772.         while(gTestChan.InProcess)
  773.         {
  774.             GetNextEvent(keyDownMask, &event);
  775.             if(event.what == keyDown) break;
  776.         }
  777.         if(SndDisposeChannel(channel, true) != noErr)
  778.         {
  779.             Error(eMajor, eMajorNoDispose);
  780.         }
  781.     }
  782.  
  783. /*    now delete the helpful message    */
  784.     GetDItem(dialog, BeepMessageId, &itemtype, &itemhdl, &itemrect);
  785.     SetIText(itemhdl, "\p");
  786. }/* TestTheBeep */
  787.  
  788.  
  789.  
  790.  
  791.  
  792.  
  793. /*----------------------------------------------------------------------------------*/
  794. /*    This function checks the sound process for the identifed beep. It processes all the
  795.     various bits of information to determine whether or not to clear the sound
  796.     channel, get another sound setup or ignore everything.  Each beep is
  797.     handled seperatly.    */
  798.     
  799. void ProcessBeep(beepchan)
  800. BeepCPtr    beepchan;
  801. {
  802.     BeepHdl            beephdl;
  803.     SndChannelPtr    channel;
  804.  
  805.     if(beepchan->InProcess == false)
  806.     {
  807.         if(beepchan->SndChannel == nil)
  808.         {
  809.             beephdl = (BeepHdl)GetResource('beep', beepchan->RsrcId);
  810.             if((beephdl == nil) || (ResError() != noErr)) 
  811.             {
  812.                 Error(eMinor, eMinorRsrc);
  813.                 beepchan->Error = true;
  814.                 return;
  815.             }
  816.             if((*beephdl)->Enabled == 1)
  817.             {
  818.                 channel = DoSound(beephdl);
  819.                 if(channel == nil)    /* check for the error    */
  820.                 {
  821.                     beepchan->InProcess = false;
  822.                     beepchan->SndChannel = nil;
  823.                     beepchan->Error = true;
  824.                 }
  825.                 else
  826.                 {
  827.                     beepchan->InProcess = true;
  828.                     beepchan->SndChannel = channel;
  829.                 }
  830.             }
  831.         }
  832.         else
  833.         {
  834.             KillBeepChannel(beepchan);
  835.         }
  836.     }
  837. }/* ProcessBeep */
  838.  
  839.  
  840.  
  841.  
  842.  
  843.  
  844. /*----------------------------------------------------------------------------------*/
  845. /*    This function is used to set up a sound and play it. All data pertinent to the
  846.     sound will be found in the Beep data resource pointed to by the passed handle.
  847.     This will allow this function to to use the latest data for the Beep.    */
  848.     
  849. SndChannelPtr DoSound(beephdl)
  850. BeepHdl        beephdl;
  851. {
  852.     Handle            sndhdl;
  853.     OSErr            error;
  854.     SndChannelPtr    channel;
  855.         
  856. /*    Load the 'snd' resource based on the Beep Type found in the Beep resource    */
  857.     sndhdl = GetResource('snd ', (*beephdl)->Type); /* rem the space in 'snd '    */
  858.     if((sndhdl == nil) || (ResError() != noErr)) 
  859.     {
  860.         Error(eMinor, eMinorNoSnd);
  861.         return(nil);
  862.     }
  863.     
  864. /*    Initalize the sound channel    */    
  865.     channel = (SndChannelPtr)nil;
  866.     error = SndNewChannel(&channel, waveTableSynth, (*beephdl)->Init, SoundIsDone);
  867.     if(error != noErr)
  868.     {
  869.         Error(eMinor, eMinorSound);
  870.         return(nil);
  871.     }
  872.  
  873. /*    play the sound    */    
  874.     error = SndPlay(channel, sndhdl, true);
  875.     if(error != noErr)
  876.     {
  877.         Error(eMinor, eMinorSPlay);
  878.         return(nil);
  879.     }
  880.     SetUpBeep(beephdl, channel);
  881.     return(channel);
  882. }/* DoSound */
  883.  
  884.  
  885.  
  886.  
  887.  
  888.  
  889.  
  890. /*----------------------------------------------------------------------------------*/
  891. /*    This function will use the initalized the sound channel, and set up the commands
  892.     as specified by the beep data resource.    */
  893.     
  894. void SetUpBeep(beephdl, channel)
  895. BeepHdl            beephdl;
  896. SndChannelPtr    channel;
  897. {
  898.     SndCommand        command;
  899.     short            count;
  900.     
  901. /*    set the desired volume    */
  902.     command.cmd = ampCmd;
  903.     command.param1 = ((*beephdl)->Volume);
  904.     command.param2 = 0;
  905.     SndDoCommand(channel, &command, false);
  906.  
  907.     for (count = 0; count < ((*beephdl)->Count); count++)
  908.     {
  909. /*    set the length of the beep and the dersired frequency    */
  910.         command.cmd = freqDurationCmd;
  911.         command.param1 = ((*beephdl)->Length) * 2;
  912.         command.param2 = ((*beephdl)->Freq);
  913.         SndDoCommand(channel, &command, false);
  914.     
  915. /*    stop the sound    */
  916.         command.cmd = quietCmd;
  917.         command.param1 = 0;
  918.         command.param2 = 0;
  919.         SndDoCommand(channel, &command, false);
  920.     
  921. /*    set the length of quite time    */
  922.         command.cmd = restCmd;
  923.         command.param1 = ((*beephdl)->QTime) * 2;
  924.         command.param2 = 0;
  925.         SndDoCommand(channel, &command, false);
  926.     }
  927.  
  928. /*    set the length of delay between the beep cycles    */
  929.         command.cmd = restCmd;
  930.         command.param1 = ((*beephdl)->Delay) * 2;
  931.         command.param2 = 0;
  932.         SndDoCommand(channel, &command, false);
  933.     
  934. /*    set the callback procedure values. The SoundDone function will be called
  935.     when this point of the queue is reached. See the SoundDone description 
  936.     for the proccessing of the SoundChannel    */
  937.     
  938.     command.cmd = callBackCmd;
  939.     command.param1 = (*beephdl)->RsrcId;
  940.     command.param2 = SetCurrentA5();
  941.     SndDoCommand(channel, &command, false);
  942.  
  943. }/* SetUpBeep */
  944.  
  945.  
  946.  
  947.  
  948.  
  949.  
  950.  
  951. /*----------------------------------------------------------------------------------*/
  952. /*    This function is used to signify the end of the sound. It will set to false the 
  953.     "gInProcess" flag. Since this is an interrupt class of routine no efforts to
  954.     move memory shall be made. This would be disasterous. The flag will be monitored
  955.     in the main event loop. When a transition to false is detected the sound channel
  956.     will be disposed of. When the interrupt command is put into the sound queue the
  957.     resource id of that beep channel is places in as well. When we arrive here the
  958.     we check for a match of the passed resource id and change only the one flag. */
  959.     
  960. pascal void SoundIsDone(channel, command)
  961. SndChannelPtr    channel;
  962. SndCommand        command;
  963. {
  964.     long    oldA5;
  965.     short    id;
  966.  
  967.     id = command.param1;                /* get the passed resource Id    */
  968.     oldA5 = SetA5(command.param2);        /* save the current A5 while setting A5 that was
  969.                                         passed in the command block.    */
  970.     if(gSopranoChan.RsrcId == id) gSopranoChan.InProcess = false;
  971.     if(gAltoChan.RsrcId == id) gAltoChan.InProcess = false;
  972.     if(gTenorChan.RsrcId == id) gTenorChan.InProcess = false;
  973.     if(gBassChan.RsrcId == id) gBassChan.InProcess = false;
  974.     if(gTestChan.RsrcId == id) gTestChan.InProcess = false;
  975.     oldA5 = SetA5(oldA5);                /* now restore the origional A5    */
  976. }/* SoundIsDone */
  977.  
  978.  
  979.  
  980.  
  981.  
  982.  
  983. /*----------------------------------------------------------------------------------*/
  984. /*    This function sets all the Beep Enable Flags.    */
  985.  
  986. void SetAllSounds()
  987. {
  988.     ForceBeepEnable(&gSopranoChan, true);
  989.     ForceBeepEnable(&gAltoChan, true);
  990.     ForceBeepEnable(&gTenorChan, true);
  991.     ForceBeepEnable(&gBassChan, true);
  992. }/* SetAllSounds */
  993.  
  994.  
  995.  
  996.  
  997.  
  998. /*----------------------------------------------------------------------------------*/
  999. /*    This function Clears all the Beep Enable Flags.    */
  1000.  
  1001. void ClearAllSounds()
  1002. {
  1003.     ForceBeepEnable(&gSopranoChan, false);
  1004.     ForceBeepEnable(&gAltoChan, false);
  1005.     ForceBeepEnable(&gTenorChan, false);
  1006.     ForceBeepEnable(&gBassChan, false);
  1007. }/* ClearAllSounds */
  1008.  
  1009.  
  1010.  
  1011.  
  1012.  
  1013. /*----------------------------------------------------------------------------------*/
  1014. /*    This function  disposes of all the beep channels. This will stop all sounds
  1015.     currently in process.  */
  1016.  
  1017. void KillSoundChannels()
  1018. {
  1019.     KillBeepChannel(&gSopranoChan);
  1020.     KillBeepChannel(&gAltoChan);
  1021.     KillBeepChannel(&gTenorChan);
  1022.     KillBeepChannel(&gBassChan);
  1023. }/* KillAllSounds */
  1024.  
  1025.  
  1026.  
  1027.  
  1028.  
  1029. /*----------------------------------------------------------------------------------*/
  1030. /*    This function disposes of the sound channel whose pointer is passed. Since this
  1031.     not alter the Beep Enable flags in the resources this is usd as only a temporary
  1032.     stoping of the beeps. The next call to "CheckForSound" will restart the beep.*/
  1033.  
  1034. void KillBeepChannel(beepchan)
  1035. BeepCPtr    beepchan;
  1036. {
  1037.     OSErr    error = 0;
  1038.  
  1039.     if(beepchan->SndChannel != nil)
  1040.     {
  1041.         error = SndDisposeChannel(beepchan->SndChannel, true);
  1042.         if(error != noErr)
  1043.         {
  1044.             beepchan->Error = true;            /*    kill this channel            */
  1045.             Error(eMajor, eMajorNoDispose);    /*    signal the error            */
  1046.          }
  1047.     }
  1048.     beepchan->InProcess = false;            /*    always leave with no beep    */
  1049.     beepchan->SndChannel = nil;                /*    and no sound channel        */
  1050. }/* KillBeepChannel */
  1051.  
  1052.  
  1053.  
  1054.  
  1055.  
  1056.  
  1057. /*----------------------------------------------------------------------------------*/
  1058. /*    This function forecs the Beep enable Flag to be the specified value in the
  1059.     identified Beep resource.    */
  1060.  
  1061. void ForceBeepEnable(beepchan, value)
  1062. BeepCPtr    beepchan;
  1063. Boolean        value;
  1064. {
  1065.     BeepHdl        beephdl;
  1066.     
  1067.     beephdl = (BeepHdl)GetResource('beep', beepchan->RsrcId);
  1068.     if((beephdl == nil) || (ResError() != noErr))
  1069.     {
  1070.         beepchan->Error = true;                /*    kill this channel    */
  1071.     }
  1072.     else
  1073.     {
  1074.         (*beephdl)->Enabled = value;        /* Clear the Beep Enable        */
  1075.         ChangedResource((Handle)beephdl);    /* mark it changed                */
  1076.         WriteResource((Handle)beephdl);        /* make the change permanent    */
  1077.     }
  1078. }/* ForceBeepEnable */
  1079.  
  1080.  
  1081.  
  1082.  
  1083.  
  1084. /*----------------------------------------------------------------------------------*/
  1085. /*    This will initalize all the necessary variables a Beep Channel. It is Important
  1086.     to note that the beep.Error will only be set to false once, here. If at any
  1087.     time during the course of this application the beep channel with this error set
  1088.     will be ignored. Any use of a resource or sound channel associated with this
  1089.     beep channel will set the Error flag.*/
  1090.  
  1091. void InitChannel(beepchan, rsrc)
  1092. BeepCPtr    beepchan;
  1093. short        rsrc;
  1094. {
  1095.     beepchan->RsrcId = rsrc;                /*    id the recource to the beep channel    */
  1096.     beepchan->Error = false;                /*    there can be no error yet            */
  1097.     beepchan->InProcess = false;            /*    and no beep                            */
  1098.     beepchan->SndChannel = nil;                /*    and no sound channel                */
  1099. }/* InitChannel */